package com.hzncc.flowable_diboot.contract.service.impl;

import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diboot.core.service.impl.BaseServiceImpl;
import com.diboot.core.util.S;
import com.hzncc.flowable_diboot.constans.Cons;
import com.hzncc.flowable_diboot.contract.entity.FieldMapping;
import com.hzncc.flowable_diboot.contract.service.FieldMappingService;
import com.hzncc.flowable_diboot.contract.vo.ContractAuditUpdateListVO;
import com.hzncc.flowable_diboot.contract.vo.ContractAuditVO;
import com.hzncc.flowable_diboot.contract.vo.ContractExtListVO;
import com.hzncc.flowable_diboot.mapper.FieldMappingMapper;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

import static org.apache.poi.sl.draw.geom.GuideIf.Op.val;


/**
 * 字段映射 相关Service实现类
 *
 * @author MyName
 * @version 1.0
 * @date 2024-09-03
 * Copyright © MyCorp
 */
@Log4j2
@Service
public class FieldMappingServiceImpl extends BaseServiceImpl<FieldMappingMapper, FieldMapping> implements FieldMappingService {
    @Override
    public <T> T jsonToEntity(Class<T> clz, String json, String code) {
        return null;
    }

    @Override
    public <T> String entityToJson(T entity, String code) {
        QueryWrapper<FieldMapping> qw = new QueryWrapper<>();
        qw.lambda().eq(FieldMapping::getCode, code);
        List<FieldMapping> mappingList = getEntityList(qw);
        if (mappingList == null || mappingList.isEmpty()) {
            throw new RuntimeException("未找到对应的字段映射关系");
        }
        JSONObject jsonObject = new JSONObject(new JSONConfig().setDateFormat("yyyy-MM-dd"));
        for (FieldMapping fieldMapping : mappingList) {
            buildJsonObject(jsonObject, fieldMapping, entity);
        }
        return jsonObject.toJSONString(0).replaceAll("\n", "");
    }

    /**
     * 构建json对象
     *
     * @param jsonObject
     * @param mapping
     * @param entity
     * @author 陈广煜
     * @date 2024-09-05
     */
    private void buildJsonObject(JSONObject jsonObject, FieldMapping mapping, Object entity) {
        log.debug("字段映射：" + mapping.getMappingField() + " -> " + mapping.getEntityField() + " -> " + mapping.getTemplate() + " -> " + mapping.getMethod());
        String dataType = mapping.getDataType();
        String fieldPath = mapping.getFieldPath();
        String entityField = mapping.getEntityField();
        String template = mapping.getTemplate();
        String method = mapping.getMethod();
        // json数组对象
        if ("array".equals(dataType)) {
            String[] e = entityField.split("\\.");
            if ("a.a.v".equals(fieldPath)) { // 实体数组对象
                List fieldValue = (List) getFieldValue(entity, e[0]);
                for (Object obj : fieldValue) {
                    List list = (List) getFieldValue(obj, e[1]);
                    if (list == null || list.isEmpty()) {
                        continue;
                    }
                    for (Object var : list) {
                        Object targetVal = getFieldValue(var, e[2]);
                        jsonObject.append(mapping.getMappingField(), Optional.ofNullable(targetVal).orElse("").toString());
                    }
                }
            } else if ("a.v".equals(fieldPath)) {
                List fieldValue = (List) getFieldValue(entity, e[0]);
                if (fieldValue != null) {
                    for (Object obj : fieldValue) {
                        Object val = getFieldValue(obj, e[1]);
                        jsonObject.append(mapping.getMappingField(), Optional.ofNullable(val).orElse("").toString());
                    }
                }
            } else if ("o.a.v".equals(fieldPath)) {
                Object fieldValue = getFieldValue(entity, e[0]);
                if (fieldValue != null) {
                    List list = (List) getFieldValue(fieldValue, e[1]);
                    if (list != null && !list.isEmpty()) {
                        for (Object o : list) {
                            Object val = getFieldValue(o, e[2]);
                            jsonObject.append(mapping.getMappingField(), Optional.ofNullable(val).orElse("").toString());
                        }
                    }
                }
            }
        } else if (!S.isBlank(template)) { // 模板字符串
            if (S.isNotBlank(entityField)) {
                String[] fields = entityField.split(",");
                List<String> valList = new ArrayList<>();
                for (String field : fields) {
                    Object fieldValue = getFieldValue(entity, field);
                    String s = StrUtil.toString(fieldValue).replace("null", "");
                    valList.add(s);
                }
                jsonObject.set(mapping.getMappingField(), format(template, valList));
            } else {
                jsonObject.set(mapping.getMappingField(), format(template, null));
            }
        } else if (S.isNotBlank(method)) { // 方法构建
            Object obj = null;
            if (method.contains(".")) {
                String beanName = method.substring(0, method.lastIndexOf("."));
                method = method.substring(method.lastIndexOf(".") + 1);
                obj = ReflectUtil.newInstance(beanName);
            } else {
                obj = this;
            }
            if (S.isNotBlank(entityField)) {
                if (entityField.contains(",")) {
                    String[] vals = entityField.split(",");
                    List params = new ArrayList();
                    for (String val : vals) {
                        Object fieldValue = getFieldValue(entity, val);
                        params.add(fieldValue);
                    }
                    Object invoke = ReflectUtil.invoke(obj, method, params);
                    jsonObject.set(mapping.getMappingField(), invoke);
                } else {
                    Object fieldValue = getFieldValue(entity, entityField);
                    Object invoke = ReflectUtil.invoke(obj, method, fieldValue);
                    jsonObject.set(mapping.getMappingField(), invoke);
                }
            } else {
                Object invoke = ReflectUtil.invoke(obj, method, entity);
                jsonObject.set(mapping.getMappingField(), invoke);
            }
        } else {
            jsonObject.set(mapping.getMappingField(), getFieldValue(entity, entityField));
        }
        log.debug("构建完成{}:{}", mapping.getMappingField(), entityField);
    }

    /**
     * 日期格式化
     *
     * @param obj
     * @return
     * @author 陈广煜
     * @date 2024-09-04
     */
    public String dateFormat(Object obj) {
        return DateUtil.format((LocalDateTime) obj, "yyyy-MM-dd");
    }

    /**
     * 获取结算方式
     *
     * @param entity 合同详情
     * @return
     * @author 陈广煜
     * @date 2024-09-04
     */
    public String getSettlementMethod(Object entity) {
        ContractAuditVO detail = (ContractAuditVO) entity;
        ContractExtListVO ext = detail.getContractExtVO();
        if (ext == null) {
            return null;
        }
        String settlement = ext.getSettlement();
        if (S.equals(settlement, "0")) { // 全款
            return String.format(Cons.FULL_PAY_TEMPLATE, ext.getFullPayStatusLabel().getLabel(), ext.getFullPayDeadlineLabel().getLabel());
        } else if (S.equals(settlement, "1")) { // 二次付款
            return String.format(Cons.PART_PAY_TEMPLATE, ext.getSecondPayStatusLabel().getLabel(), ext.getSecondFirstPayDeadline(), ext.getSecondFirstAmount(), ext.getSecondLastAmount(), ext.getSecondLastPayDeadline());
        } else if (S.equals(settlement, "2")) {// 三次付款
            return String.format(Cons.THIRD_PART_PAY_TEMPLATE_ID, ext.getThirdPayStatusLabel().getLabel()
                    , ext.getThirdPayFirstDeadline(), ext.getThirdPayFirstAmount(), ext.getThirdPaySecondCondition()
                    , ext.getThirdPaySecondDeadline(), ext.getThirdPaySecondAmount()
                    , ext.getThirdPayLastAmount(), ext.getThirdPayLastDeadline());
        }
        return "";
    }

    /**
     * 获取八、结算条款
     *
     * @param entity
     * @return
     * @author 陈广煜
     * @date 2024-09-04
     */
    public String getEight(Object entity) {
        String settlementMethod = getSettlementMethod(entity);
        String prefix = "八、结算方式及期限：";
        return prefix + settlementMethod;
    }

    /**
     * 获取十一、违约责任
     *
     * @param list
     * @return
     * @author 陈广煜
     * @date 2024-09-05
     */
    public String getXI(List list) {
        String val = "十一、违约责任：\r\n";
        return getResp(list, val);
    }

    /**
     * 获取十一、违约责任
     *
     * @param list
     * @return
     * @author 陈广煜
     * @date 2024-09-05
     */
    public String getXI2(List list) {
        String val = "";
        return getResp(list, val);
    }

    private String getResp(List list, String val) {
        String a = (String) list.get(0);
        String b = (String) list.get(1);
        String c = (String) list.get(2);
        String d = (String) list.get(3);
        if (S.equals("true", a)) {
            val += "（1）需方未依约按期提货，且无书面延迟提货的通知，每逾期一日，应按合同总金额的万分之五支付违约金。逾期超过七天，供方有权解除合同。\r\n";
        }
        if (S.equals("true", b)) {
            val += "（2）非因产品质量问题，需方无权要求更换订购的全部产品。合同的变更，需方应以书面形式通知供方，供方在收到通知后3日内作出答复。不同意变更，则双方应继续履行原合同。同意变更，则更换产品的差价及补偿费由需方承担，根据更换产品的具体情况可另签补充协议。\r\n";
        }
        if (S.equals("true", c)) {
            val += "（3）需方逾期付款，每逾期一日，应按合同总金额的千分之一支付违约金。逾期超过七天，供方有权对所出售的设备采取加密手段，由此导致设备无法使用对需方造成的全部损失由需方自行承担。\r\n";
        }
        if (S.equals("true", d)) {
            val += "（4）在需方未依约付清货款前，以上设备的所有权仍属供方所有，供方可随时主张权利。";
        }
        return val;
    }

    /**
     * 格式化模板
     *
     * @param template
     * @param valList
     * @return
     * @author 陈广煜
     * @date 2024-09-04
     */
    private String format(String template, List<String> valList) {
        if (valList == null) {
            return template;
        }
        for (int i = 0; i < valList.size(); i++) {
            template = template.replace("$" + (i + 1), valList.get(i));
        }
        return template;
    }

    /**
     * 获取实体类字段的值
     *
     * @param entity
     * @param fieldName
     * @return
     * @author 陈广煜
     * @date 2024-09-03
     */
    public Object getFieldValue(Object entity, String fieldName) {
        if (entity == null || S.isBlank(fieldName)) {
            return null;
        }
        if (fieldName.contains(".")) {
            String end = fieldName.substring(fieldName.indexOf(".") + 1);
            String first = fieldName.substring(0, fieldName.indexOf("."));
            return getFieldValue(ReflectUtil.getFieldValue(entity, first), end);
        } else {
            if (entity instanceof Map) {
                return ((Map) entity).get(fieldName);
            }
            return ReflectUtil.getFieldValue(entity, fieldName);
        }
    }

    /**
     * 阿拉伯数字转大写
     *
     * @param number
     * @return
     * @author 陈广煜
     * @date 2024-09-05
     */
    public String convertToChinesNumber(Object number) {
        BigDecimal num = (BigDecimal) number;
        if (num == null) {
            return "";
        }
        // 阿拉伯数字转大写
        return NumberChineseFormatter.format(num.doubleValue(), true, true);
    }

    /**
     * 验收标准
     *
     * @param val
     * @return
     * @author 陈广煜
     * @date 2024-09-12
     */
    public String acceptanceCriteria(Object val) {
        return Objects.equals(val, "1") ? "七、验收标准、方法及提出异议的期限：货物验收标准按供方产品说明书标准验收。需方在到货后五日内应及时收货并开箱验货，如发现货物与装箱单不符，应在到货之日起五日内书面提出异议，超过规定的期限未提出异议，则视为供方交货物品符合合同约定。"
                : "七、验收标准、方法及提出异议的期限：货物验收标准按供方产品说明书标准验收。需方在到货后七日内进行开机运行验收，以机床正常运行为合格标准。如有异议，需方应在到货后7日内书面提出。若需方未在七日内开机验收或者未在开机验收后7日内提出书面异议，视为交付的产品完全符合合同的约定。";
    }

    /**
     * 获取合同执行情况
     *
     * @param entity
     * @return
     */
    public String getContractExecStatus(Object entity) {
        ContractAuditVO contractAuditVO = (ContractAuditVO) entity;
        ContractAuditUpdateListVO contractAuditUpdateVO = contractAuditVO.getContractAuditUpdateVO();
        String invoiceStatus = contractAuditUpdateVO.getInvoiceStatus();
        String sendOutStatus = contractAuditUpdateVO.getSendOutStatus();
        if (S.equals(invoiceStatus, "2") && S.equals(sendOutStatus, "1")) {  // 未开票未发货
            return "10";
        } else if (!S.equals(invoiceStatus, "2") && !S.equals(sendOutStatus, "1")) { // 已开票已发货
            return "30";
        } else if (S.equals(invoiceStatus, "2") && !S.equals(sendOutStatus, "1")) { // 已发货未开票
            return "20";
        } else {
            return "";
        }
    }

}